/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package automatolfa;

import java.util.ArrayList;
import java.util.StringTokenizer;

/**
 *
 * @author 090665
 *
 * REPRESENTA O AUTOMATO (GRAFO)
 *
 */
public class Automato {
    private ArrayList<Estado> _LstEstado;
    private String _Nome;

    /**
     * @return the _EstadoInicial
     */
    public ArrayList<Estado> getEstadoInicial() {
        return _LstEstado;
    }

    /**
     * @param EstadoInicial the _EstadoInicial to set
     */
    public void setEstadoInicial(ArrayList<Estado> EstadoInicial) {
        this._LstEstado = EstadoInicial;
    }

    /**
     * @return the _Nome
     */
    public String getNome() {
        return _Nome;
    }

    /**
     * @param Nome the _Nome to set
     */
    public void setNome(String Nome) {
        this._Nome = Nome;
    }
    
    public Automato(String nome)
    {
        _Nome = nome;
        _LstEstado = new ArrayList<Estado>();
    }

    /**
     * CRIA NOVO UM TOKEN NO AUTOMATO
     * @param expressao - TOKEN CONTENDO A EXPRESSÃO DO AUTOMATO
     */
    public void NovoToken(String expressao)
    {
        
            // CRIA UM NOVO TOKEN SIMPLES
            NovoTokenSimples(expressao);
     
    }

    /**
     * CRIA UM TOKEN SIMPLES (CADA CARACTER É UMA TRANSIÇÃO)
     * @param expressao - EXPRESSÃO CONTENDO A PALAVRA (TOKEN)
     */
    private void NovoTokenSimples(String expressao)
    {
        // CÓDIGO GENÉRICO PARA MONTAR TOKEN SIMPLES
        Estado eAtual = null;
        Estado eAntigo = null;
        char c = ' ';

        // Estados Intermediários
        for (int i = 0; i < expressao.length(); i++) {
            eAtual = new Estado("q" + i); // Estado Intermediário i
            if(eAntigo != null) // Adiciona o estado antigo somente
            {
                eAntigo.NovaTransicao(eAtual, c); // Aponta o estado antigo para o estado atual com o char antigo
                NovoEstado(eAntigo); // Adiciona o estado antigo
            }
            c = expressao.charAt(i); // Pega o char Atual
            eAntigo = eAtual; // Atualiza o estado antigo
        }
        eAtual = new Estado("qr"); // Estado Final
        eAntigo.NovaTransicao(eAtual, c);
        NovoEstado(eAntigo);

        //Estado Final
        NovoEstado(eAtual);
    }

    /**
     * CRIA UM NOVO ESTADO NO AUTOMATO
     * @param nomeEstado - ESTADO
     */
    public void NovoEstado(Estado nomeEstado)
    {
        _LstEstado.add(nomeEstado);
    }

    /**
     * VERIFICA SE A PALAVRA PASSADA É UM TOKEN OU NÃO
     * @param palavra - PALAVRA A SER VALIDADA
     * @return "TRUE" É UM TOKEN; "FALSE" NÃO É UM TOKEN
     */
    public Boolean ValidaPalavra(String palavra)
    {
        // VERIFICA SE O AUTOMATO TEM ESTADOS (NÓS)
        if(_LstEstado.size() > 0)
        {
            Estado q = getEstadoInicial(_LstEstado); // PEGA O PRIMEIRO ESTADO (NÓ)

            // PERCORRE OS CARACTERES DA PALAVRA
            for(int idxPalavra = 0; idxPalavra < palavra.length(); idxPalavra++)
            {
                // VERIFICA SE O ESTADO (NÓ) TEM TRANSIÇÕES (ARCOS)
                if(q.getLstTransicao().size() <= 0)
                    return false;

                // PERCORRE AS TRANSIÇÕES (ARCOS) DO ESTADO (NÓ) ATUAL
                for(int i = 0; i < q.getLstTransicao().size(); i++)
                {
                    // VERIFICA SE O SIMBOLO DA TRANSIÇÃO (ARCO) CORRESPONDE AO CARACTER ATUAL DA PALAVRA QUE ESTÁ SENDO PERCORRIDA
                    if(q.getLstTransicao().get(i).getSimbolo() == palavra.charAt(idxPalavra))
                    {
                        // ENTÃO VAI PARA O ESTADO (NÓ) DESTINO DESTA TRANSIÇÃO (ARCO)
                        q = q.getLstTransicao().get(i).getDestino();
                        break;
                    }

                    // SE O ESTADO NÃO TEM MAIS TRANSIÇÕES (ARCOS)
                    if(i == q.getLstTransicao().size() -1)
                        // ENTÃO A PALAVRA É INVÁLIDA
                        return false;
                }
            }

            // SE PERCORREU TODOS OS ESTADOS E CHEGOU NO ESTADO FINAL
            if(q.getNome().equals("qr"))
                // ENTÃO O ESTADO É VÁLIDO
                return true;
        }

        // ESTADO INVÁLIDO
        return false;
    }

    public Estado getEstadoInicial(ArrayList<Estado> estados)
    {
        for(Estado e : estados)
        {
            if(e.getNome().equals("q0"))
                return e;
        }

        return estados.get(0);
    }
    
    
    
    public static Automato AutomatoVariavel()
    {
        Automato a = new Automato("NomeVariavel");

        Estado q0 = new Estado("q0");
        Estado q1 = new Estado("qr");
        Estado q2 = new Estado("qr");
        Estado q3 = new Estado("qr");

        // Q0 -> Q1
        for (char c = 'a'; c <= 'z'; c++) {
            q0.NovaTransicao(q1, c);
        }
        for (char c = 'A'; c <= 'Z'; c++) {
            q0.NovaTransicao(q1, c);
        }
        q0.NovaTransicao(q1, '_');

        // Q1 -> Q1
        for (char c = 'a'; c <= 'z'; c++) {
            q1.NovaTransicao(q1, c);
        }
        for (char c = 'A'; c <= 'Z'; c++) {
            q1.NovaTransicao(q1, c);
        }
        q1.NovaTransicao(q1, '_');
        for (char c2 = '0'; c2 <= '9'; c2++) {
            q1.NovaTransicao(q1, c2);
        }

        a.NovoEstado(q0);
        a.NovoEstado(q1);

        return a;
    }

    //TODO: implementar public static Automato AutomatoFloat()
    public static Automato AutomatoFloat()
    {
        Automato a = new Automato("ValorFloat");
        return a;        
    }
    
    public static Automato AutomatoInteiro()
    {
        Automato a = new Automato("ValorInt");

        Estado q0 = new Estado("q0");
        Estado q1 = new Estado("qr");

        for (char c = '0'; c <= '9'; c++) {
            q0.NovaTransicao(q1, c);
        }

        for (char c = '0'; c <= '9'; c++) {
            q1.NovaTransicao(q1, c);
        }

        a.NovoEstado(q0);
        a.NovoEstado(q1);

        return a;
    }

    public static Automato AutomatoChar()
    {
        Automato a = new Automato("ValorChar");

        Estado q0 = new Estado("q0");
        Estado q1 = new Estado("q1");
        Estado q2 = new Estado("q2");
        Estado q3 = new Estado("qr");

        q0.NovaTransicao(q1, '\'');

        // Q1 -> Q2
        for (char c = 'a'; c <= 'z'; c++) {
            q1.NovaTransicao(q2, c);
        }
        for (char c = 'A'; c <= 'Z'; c++) {
            q1.NovaTransicao(q2, c);
        }
        q1.NovaTransicao(q2, '\0');
        q1.NovaTransicao(q2, ' ');
        q1.NovaTransicao(q2, '_');

        
        q2.NovaTransicao(q3, '\'');

        a.NovoEstado(q0);
        a.NovoEstado(q1);
        a.NovoEstado(q2);
        a.NovoEstado(q3);

        return a;
    }
}
